// 改函数的主要作用是完成依赖收集及订阅发布；订阅发布只是通知watcher更新了，具体进行什么操作由watcher实现
function Observer(data){
    this.data = data;
    this.walk(data);
}

Observer.prototype = {
    walk: function(data){
        let self = this;
        Object.keys(data).forEach(function(key){
            self.defineReactive(data, key, data[key]);
        });
    },

    defineReactive: function(data, key, val){
        // dep是一个容器，用于收集观察者
        // 值得注意的是由于递归调用，其实每个属性都有一个与其对应的dep容器
        var dep = new Dep();
        // 值得注意的是这里如果有 a{b:{c:[]}}; 则 a.b 及 a.b.c 都会被定义
        var childObj = observer(val);
        Object.defineProperty(data, key, {
            enumerable: true,
            configurable: true,
            get: function getter(){
                if(Dep.target){
                    dep.addSub(Dep.target);
                }
                return val;
            },
            set: function setter(newVal){
                if(newVal === val){
                    return;
                }
                val = newVal;
                dep.notify();
            }
        });
    }
};

// 改函数在Vue初始化时会被调用
// 改函数会被递归调用，知道解析到最内存的属性值
function observer(value, vm){
    if(!value || typeof value !== 'object'){
        return;
    }
    return new Observer(value);
}

// 定义一个watcher容器
// 每个属性都有一个对应的dep容器
function Dep(){
    this.subs = [];
}

Dep.prototype = {
    addSub: function(sub){
        this.subs.push(sub);
    },
    notify: function(){
        this.subs.forEach(function(sub){
            sub.update();
        });
    }
};

// 用于缓存当前watcher对象
Dep.target = null;